//! # 配置缓存模块
//!
//! 提供配置的本地缓存功能，支持内存缓存、文件缓存等多种缓存策略，
//! 确保在配置服务器不可用时仍能提供配置服务。
//!
//! ## 核心功能
//!
//! * **内存缓存** - 基于HashMap的高速内存缓存
//! * **文件缓存** - 持久化文件缓存，支持服务重启后恢复
//! * **TTL支持** - 缓存过期时间管理
//! * **LRU淘汰** - 最近最少使用缓存淘汰策略
//! * **缓存预热** - 启动时预加载常用配置
//! * **缓存统计** - 命中率、访问统计等指标

use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::{Duration, SystemTime};

use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use tokio::fs;
use tokio::sync::RwLock;
use tracing::{debug, error, info, warn};

use crate::RustCloudConfig;
use crate::core::*;
use super::{ConfigCache, ConfigEnvironment, ConfigClientError, ClientResult};

/// 缓存条目
#[derive(Debug, Clone, Serialize, Deserialize)]
struct CacheEntry {
    /// 配置内容
    config: RustCloudConfig,
    /// 创建时间
    created_at: SystemTime,
    /// 最后访问时间
    last_accessed: SystemTime,
    /// 访问次数
    access_count: u64,
    /// TTL（生存时间）
    ttl: Duration,
}

impl CacheEntry {
    /// 创建新的缓存条目
    fn new(config: RustCloudConfig, ttl: Duration) -> Self {
        let now = SystemTime::now();
        Self {
            config,
            created_at: now,
            last_accessed: now,
            access_count: 0,
            ttl,
        }
    }

    /// 检查是否过期
    fn is_expired(&self) -> bool {
        self.created_at.elapsed().unwrap_or_default() > self.ttl
    }

    /// 更新访问信息
    fn update_access(&mut self) {
        self.last_accessed = SystemTime::now();
        self.access_count += 1;
    }
}

/// 内存配置缓存
pub struct MemoryConfigCache {
    /// 缓存存储
    cache: Arc<RwLock<HashMap<String, CacheEntry>>>,
    /// 默认TTL
    default_ttl: Duration,
    /// 最大缓存条目数
    max_entries: usize,
    /// 缓存统计
    stats: Arc<RwLock<CacheStats>>,
}

/// 缓存统计信息
#[derive(Debug, Default)]
pub struct CacheStats {
    /// 命中次数
    pub hits: u64,
    /// 未命中次数
    pub misses: u64,
    /// 过期淘汰次数
    pub evictions: u64,
    /// 写入次数
    pub puts: u64,
}

impl CacheStats {
    /// 计算命中率
    pub fn hit_rate(&self) -> f64 {
        let total = self.hits + self.misses;
        if total == 0 {
            0.0
        } else {
            self.hits as f64 / total as f64
        }
    }
}

impl MemoryConfigCache {
    /// 创建新的内存缓存
    pub fn new(default_ttl: Duration) -> Self {
        Self {
            cache: Arc::new(RwLock::new(HashMap::new())),
            default_ttl,
            max_entries: 1000, // 默认最大1000个条目
            stats: Arc::new(RwLock::new(CacheStats::default())),
        }
    }

    /// 设置最大缓存条目数
    pub fn with_max_entries(mut self, max_entries: usize) -> Self {
        self.max_entries = max_entries;
        self
    }

    /// 生成缓存键
    fn generate_cache_key(&self, environment: &ConfigEnvironment) -> String {
        format!("{}:{}:{}", environment.application, environment.profile, environment.label)
    }

    /// 清理过期条目
    async fn cleanup_expired(&self) {
        let mut cache = self.cache.write().await;
        let mut stats = self.stats.write().await;
        
        let expired_keys: Vec<String> = cache
            .iter()
            .filter(|(_, entry)| entry.is_expired())
            .map(|(key, _)| key.clone())
            .collect();

        for key in expired_keys {
            cache.remove(&key);
            stats.evictions += 1;
            debug!("🧹 清理过期缓存条目: {}", key);
        }
    }

    /// 执行LRU淘汰
    async fn evict_lru_if_needed(&self) {
        let mut cache = self.cache.write().await;
        
        if cache.len() <= self.max_entries {
            return;
        }

        // 找到最近最少使用的条目
        let mut lru_key: Option<String> = None;
        let mut oldest_access = SystemTime::now();

        for (key, entry) in cache.iter() {
            if entry.last_accessed < oldest_access {
                oldest_access = entry.last_accessed;
                lru_key = Some(key.clone());
            }
        }

        if let Some(key) = lru_key {
            cache.remove(&key);
            let mut stats = self.stats.write().await;
            stats.evictions += 1;
            debug!("🗑️ LRU淘汰缓存条目: {}", key);
        }
    }

    /// 获取缓存统计
    pub async fn get_stats(&self) -> CacheStats {
        let stats = self.stats.read().await;
        CacheStats {
            hits: stats.hits,
            misses: stats.misses,
            evictions: stats.evictions,
            puts: stats.puts,
        }
    }
}

#[async_trait]
impl ConfigCache for MemoryConfigCache {
    async fn get(&self, environment: &ConfigEnvironment) -> ClientResult<Option<RustCloudConfig>> {
        let key = self.generate_cache_key(environment);
        debug!("🔍 查找缓存条目: {}", key);

        // 先清理过期条目
        self.cleanup_expired().await;

        let mut cache = self.cache.write().await;
        let mut stats = self.stats.write().await;

        if let Some(entry) = cache.get_mut(&key) {
            if entry.is_expired() {
                // 条目已过期，移除并返回None
                cache.remove(&key);
                stats.misses += 1;
                stats.evictions += 1;
                debug!("⏰ 缓存条目已过期: {}", key);
                Ok(None)
            } else {
                // 更新访问信息
                entry.update_access();
                stats.hits += 1;
                debug!("🎯 缓存命中: {}", key);
                Ok(Some(entry.config.clone()))
            }
        } else {
            stats.misses += 1;
            debug!("❌ 缓存未命中: {}", key);
            Ok(None)
        }
    }

    async fn put(&self, environment: &ConfigEnvironment, config: &RustCloudConfig) -> ClientResult<()> {
        let key = self.generate_cache_key(environment);
        debug!("💾 保存到缓存: {}", key);

        // 检查是否需要LRU淘汰
        self.evict_lru_if_needed().await;

        let entry = CacheEntry::new(config.clone(), self.default_ttl);
        
        {
            let mut cache = self.cache.write().await;
            cache.insert(key.clone(), entry);
        }

        {
            let mut stats = self.stats.write().await;
            stats.puts += 1;
        }

        debug!("✅ 缓存保存成功: {}", key);
        Ok(())
    }

    async fn remove(&self, environment: &ConfigEnvironment) -> ClientResult<()> {
        let key = self.generate_cache_key(environment);
        debug!("🗑️ 移除缓存条目: {}", key);

        let mut cache = self.cache.write().await;
        if cache.remove(&key).is_some() {
            debug!("✅ 缓存条目移除成功: {}", key);
        } else {
            debug!("⚠️ 缓存条目不存在: {}", key);
        }

        Ok(())
    }

    async fn clear(&self) -> ClientResult<()> {
        info!("🧹 清空所有缓存");

        let mut cache = self.cache.write().await;
        cache.clear();

        let mut stats = self.stats.write().await;
        *stats = CacheStats::default();

        info!("✅ 缓存已清空");
        Ok(())
    }

    async fn is_expired(&self, environment: &ConfigEnvironment) -> ClientResult<bool> {
        let key = self.generate_cache_key(environment);
        
        let cache = self.cache.read().await;
        if let Some(entry) = cache.get(&key) {
            Ok(entry.is_expired())
        } else {
            Ok(true) // 不存在的条目视为已过期
        }
    }
}

#[async_trait]
impl ConfigurationCache for MemoryConfigCache {
    async fn get(&self, environment: &ConfigEnvironment) -> ConfigurationResult<Option<ConfigurationData>> {
        if let Ok(Some(config)) = self.get_config(environment).await {
            let data = ConfigurationData {
                environment: environment.clone(),
                config,
                version: "cached".to_string(),
                last_modified: SystemTime::now(),
                source: "memory_cache".to_string(),
                properties: HashMap::new(),
            };
            Ok(Some(data))
        } else {
            Ok(None)
        }
    }
    
    async fn put(&self, data: &ConfigurationData) -> ConfigurationResult<()> {
        self.put_config(&data.environment, &data.config).await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
    }
    
    async fn remove(&self, environment: &ConfigEnvironment) -> ConfigurationResult<()> {
        let key = self.generate_cache_key(environment);
        debug!("🗑️ 移除缓存条目: {}", key);

        let mut cache = self.cache.write().await;
        if cache.remove(&key).is_some() {
            debug!("✅ 缓存条目移除成功: {}", key);
        } else {
            debug!("⚠️ 缓存条目不存在: {}", key);
        }

        Ok(())
    }
    
    async fn clear(&self) -> ConfigurationResult<()> {
        info!("🧹 清空所有缓存");

        let mut cache = self.cache.write().await;
        cache.clear();

        let mut stats = self.stats.write().await;
        *stats = CacheStats::default();

        info!("✅ 缓存已清空");
        Ok(())
    }
    
    async fn contains(&self, environment: &ConfigEnvironment) -> ConfigurationResult<bool> {
        Ok(self.get_config(environment).await.unwrap_or(None).is_some())
    }
    
    async fn is_expired(&self, environment: &ConfigEnvironment) -> ConfigurationResult<bool> {
        let key = self.generate_cache_key(environment);
        
        let cache = self.cache.read().await;
        if let Some(entry) = cache.get(&key) {
            Ok(entry.is_expired())
        } else {
            Ok(true) // 不存在的条目视为已过期
        }
    }
    
    async fn get_stats(&self) -> ConfigurationResult<CacheStatistics> {
        let stats = MemoryConfigCache::get_stats(self).await;
        Ok(CacheStatistics {
            hit_count: stats.hits,
            miss_count: stats.misses,
            hit_rate: stats.hit_rate(),
            size: {
                let cache = self.cache.read().await;
                cache.len()
            },
            max_capacity: self.max_entries,
            expired_count: stats.evictions,
        })
    }
    
    async fn refresh(&self, environment: &ConfigEnvironment) -> ConfigurationResult<()> {
        // 内存缓存的刷新就是移除条目，让下次访问重新获取
        self.remove(environment).await
    }
}

/// 文件配置缓存
pub struct FileConfigCache {
    /// 内存缓存（作为L1缓存）
    memory_cache: MemoryConfigCache,
    /// 缓存目录
    cache_dir: PathBuf,
    /// 是否启用文件缓存
    file_cache_enabled: bool,
}

impl FileConfigCache {
    /// 创建新的文件缓存
    pub fn new(cache_dir: PathBuf, default_ttl: Duration) -> Self {
        Self {
            memory_cache: MemoryConfigCache::new(default_ttl),
            cache_dir,
            file_cache_enabled: true,
        }
    }

    /// 禁用文件缓存
    pub fn disable_file_cache(mut self) -> Self {
        self.file_cache_enabled = false;
        self
    }

    /// 生成文件路径
    fn get_file_path(&self, environment: &ConfigEnvironment) -> PathBuf {
        let filename = format!("{}_{}_{}.json", 
            environment.application, environment.profile, environment.label);
        self.cache_dir.join(filename)
    }

    /// 从文件加载配置
    async fn load_from_file(&self, environment: &ConfigEnvironment) -> ClientResult<Option<CacheEntry>> {
        if !self.file_cache_enabled {
            return Ok(None);
        }

        let file_path = self.get_file_path(environment);
        
        if !file_path.exists() {
            return Ok(None);
        }

        match fs::read_to_string(&file_path).await {
            Ok(content) => {
                match serde_json::from_str::<CacheEntry>(&content) {
                    Ok(entry) => {
                        debug!("📂 从文件加载缓存: {:?}", file_path);
                        Ok(Some(entry))
                    }
                    Err(e) => {
                        warn!("⚠️ 文件缓存解析失败: {}", e);
                        // 删除损坏的缓存文件
                        let _ = fs::remove_file(&file_path).await;
                        Ok(None)
                    }
                }
            }
            Err(e) => {
                warn!("⚠️ 读取文件缓存失败: {}", e);
                Ok(None)
            }
        }
    }

    /// 保存到文件
    async fn save_to_file(&self, environment: &ConfigEnvironment, entry: &CacheEntry) -> ClientResult<()> {
        if !self.file_cache_enabled {
            return Ok(());
        }

        // 确保缓存目录存在
        if let Err(e) = fs::create_dir_all(&self.cache_dir).await {
            warn!("⚠️ 创建缓存目录失败: {}", e);
            return Ok(()); // 不因为文件缓存失败而影响主流程
        }

        let file_path = self.get_file_path(environment);
        
        match serde_json::to_string_pretty(entry) {
            Ok(content) => {
                if let Err(e) = fs::write(&file_path, content).await {
                    warn!("⚠️ 保存文件缓存失败: {}", e);
                } else {
                    debug!("💾 保存到文件缓存: {:?}", file_path);
                }
            }
            Err(e) => {
                warn!("⚠️ 序列化缓存条目失败: {}", e);
            }
        }

        Ok(())
    }

    /// 从文件删除
    async fn remove_from_file(&self, environment: &ConfigEnvironment) -> ClientResult<()> {
        if !self.file_cache_enabled {
            return Ok(());
        }

        let file_path = self.get_file_path(environment);
        
        if file_path.exists() {
            if let Err(e) = fs::remove_file(&file_path).await {
                warn!("⚠️ 删除文件缓存失败: {}", e);
            } else {
                debug!("🗑️ 删除文件缓存: {:?}", file_path);
            }
        }

        Ok(())
    }

    /// 预热缓存
    pub async fn warmup(&self) -> ClientResult<()> {
        if !self.file_cache_enabled {
            return Ok(());
        }

        info!("🔥 开始缓存预热...");

        let mut entries = fs::read_dir(&self.cache_dir).await
            .map_err(|_| ConfigClientError::CacheError("无法读取缓存目录".to_string()))?;

        let mut loaded_count = 0;

        while let Some(entry) = entries.next_entry().await.unwrap_or(None) {
            let path = entry.path();
            if path.is_file() && path.extension().map_or(false, |ext| ext == "json") {
                if let Ok(content) = fs::read_to_string(&path).await {
                    if let Ok(cache_entry) = serde_json::from_str::<CacheEntry>(&content) {
                        if !cache_entry.is_expired() {
                            // 将有效的缓存条目加载到内存
                            if let Some(filename) = path.file_stem().and_then(|s| s.to_str()) {
                                let parts: Vec<&str> = filename.split('_').collect();
                                if parts.len() == 3 {
                                    let environment = ConfigEnvironment {
                                        application: parts[0].to_string(),
                                        profile: parts[1].to_string(),
                                        label: parts[2].to_string(),
                                    };
                                    
                                    let config_data = ConfigurationData {
                                        environment: environment.clone(),
                                        config: cache_entry.config.clone(),
                                        version: "cached".to_string(),
                                        last_modified: cache_entry.created_at,
                                        source: "file_cache_preload".to_string(),
                                        properties: HashMap::new(),
                                    };
                                    
                                    if let Err(e) = self.memory_cache.put(&config_data).await {
                                        warn!("⚠️ 预热缓存失败: {}", e);
                                    } else {
                                        loaded_count += 1;
                                    }
                                }
                            }
                        } else {
                            // 删除过期的文件缓存
                            let _ = fs::remove_file(&path).await;
                        }
                    }
                }
            }
        }

        info!("✅ 缓存预热完成，加载了 {} 个配置", loaded_count);
        Ok(())
    }
}

#[async_trait]
impl ConfigCache for FileConfigCache {
    async fn get_config(&self, environment: &ConfigEnvironment) -> ClientResult<Option<RustCloudConfig>> {
        // 首先尝试内存缓存
        if let Some(config) = self.memory_cache.get_config(environment).await? {
            return Ok(Some(config));
        }

        // 如果内存缓存没有，尝试文件缓存
        if let Some(entry) = self.load_from_file(environment).await? {
            if !entry.is_expired() {
                // 将文件缓存加载到内存缓存
                if let Err(e) = self.memory_cache.put_config(environment, &entry.config).await {
                    warn!("⚠️ 加载文件缓存到内存失败: {}", e);
                }
                return Ok(Some(entry.config));
            } else {
                // 删除过期的文件缓存
                let _ = self.remove_from_file(environment).await;
            }
        }

        Ok(None)
    }

    async fn put_config(&self, environment: &ConfigEnvironment, config: &RustCloudConfig) -> ClientResult<()> {
        // 保存到内存缓存
        self.memory_cache.put_config(environment, config).await?;

        // 保存到文件缓存
        let entry = CacheEntry::new(config.clone(), self.memory_cache.default_ttl);
        self.save_to_file(environment, &entry).await?;

        Ok(())
    }
}

#[async_trait]
impl ConfigurationCache for FileConfigCache {
    async fn get(&self, environment: &ConfigEnvironment) -> ConfigurationResult<Option<ConfigurationData>> {
        if let Ok(Some(config)) = ConfigCache::get_config(self, environment).await {
            let data = ConfigurationData {
                environment: environment.clone(),
                config,
                version: "cached".to_string(),
                last_modified: SystemTime::now(),
                source: "file_cache".to_string(),
                properties: HashMap::new(),
            };
            Ok(Some(data))
        } else {
            Ok(None)
        }
    }
    
    async fn put(&self, data: &ConfigurationData) -> ConfigurationResult<()> {
        self.put_config(&data.environment, &data.config).await
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
    }
    
    async fn remove(&self, environment: &ConfigEnvironment) -> ConfigurationResult<()> {
        self.memory_cache.remove(environment).await?;
        let _ = self.remove_from_file(environment).await;
        Ok(())
    }
    
    async fn clear(&self) -> ConfigurationResult<()> {
        self.memory_cache.clear().await?;
        // 清理所有文件缓存
        if self.cache_dir.exists() {
            let _ = std::fs::remove_dir_all(&self.cache_dir);
            let _ = std::fs::create_dir_all(&self.cache_dir);
        }
        Ok(())
    }
    
    async fn contains(&self, environment: &ConfigEnvironment) -> ConfigurationResult<bool> {
        Ok(self.get_config(environment).await.unwrap_or(None).is_some())
    }
    
    async fn is_expired(&self, environment: &ConfigEnvironment) -> ConfigurationResult<bool> {
        self.memory_cache.is_expired(environment).await
            .map_err(|e| e.into())
    }
    
    async fn get_stats(&self) -> ConfigurationResult<CacheStatistics> {
        let stats = self.memory_cache.get_stats().await;
        Ok(CacheStatistics {
            hit_count: stats.hits,
            miss_count: stats.misses,
            hit_rate: stats.hit_rate(),
            size: {
                let cache = self.memory_cache.cache.read().await;
                cache.len()
            },
            max_capacity: self.memory_cache.max_entries,
            expired_count: stats.evictions,
        })
    }
    
    async fn refresh(&self, environment: &ConfigEnvironment) -> ConfigurationResult<()> {
        // 文件缓存的刷新就是移除条目，让下次访问重新获取
        self.remove(environment).await
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::TempDir;

    #[tokio::test]
    async fn test_memory_cache_basic_operations() {
        let cache = MemoryConfigCache::new(Duration::from_secs(60));
        let environment = ConfigEnvironment {
            application: "test-app".to_string(),
            profile: "dev".to_string(),
            label: "main".to_string(),
        };
        let config = RustCloudConfig::default();

        // 测试缓存未命中
        assert!(cache.get_config(&environment).await.unwrap().is_none());

        // 测试保存和获取
        cache.put_config(&environment, &config).await.unwrap();
        assert!(cache.get_config(&environment).await.unwrap().is_some());

        // 测试移除
        cache.remove(&environment).await.unwrap();
        assert!(cache.get_config(&environment).await.unwrap().is_none());
    }

    #[tokio::test]
    async fn test_memory_cache_expiration() {
        let cache = MemoryConfigCache::new(Duration::from_millis(100));
        let environment = ConfigEnvironment {
            application: "test-app".to_string(),
            profile: "dev".to_string(),
            label: "main".to_string(),
        };
        let config = RustCloudConfig::default();

        // 保存到缓存
        cache.put_config(&environment, &config).await.unwrap();
        assert!(cache.get_config(&environment).await.unwrap().is_some());

        // 等待过期
        tokio::time::sleep(Duration::from_millis(150)).await;
        assert!(cache.get_config(&environment).await.unwrap().is_none());
    }

    #[tokio::test]
    async fn test_file_cache_persistence() {
        let temp_dir = TempDir::new().unwrap();
        let cache = FileConfigCache::new(temp_dir.path().to_path_buf(), Duration::from_secs(60));
        
        let environment = ConfigEnvironment {
            application: "test-app".to_string(),
            profile: "dev".to_string(),
            label: "main".to_string(),
        };
        let config = RustCloudConfig::default();

        // 保存到缓存
        cache.put_config(&environment, &config).await.unwrap();

        // 创建新的缓存实例（模拟重启）
        let new_cache = FileConfigCache::new(temp_dir.path().to_path_buf(), Duration::from_secs(60));
        
        // 预热缓存
        new_cache.warmup().await.unwrap();
        
        // 应该能够从文件缓存中加载
        assert!(new_cache.get_config(&environment).await.unwrap().is_some());
    }

    #[tokio::test]
    async fn test_cache_stats() {
        let cache = MemoryConfigCache::new(Duration::from_secs(60));
        let environment = ConfigEnvironment {
            application: "test-app".to_string(),
            profile: "dev".to_string(),
            label: "main".to_string(),
            version: None,
            state: None,
        };
        let config = RustCloudConfig::default();

        // 测试未命中
        let _ = cache.get_config(&environment).await;
        let stats = cache.get_stats().await;
        assert_eq!(stats.misses, 1);
        assert_eq!(stats.hits, 0);

        // 测试命中
        cache.put_config(&environment, &config).await.unwrap();
        let _ = cache.get_config(&environment).await;
        let stats = cache.get_stats().await;
        assert_eq!(stats.hits, 1);
        assert_eq!(stats.puts, 1);
        assert!(stats.hit_rate() > 0.0);
    }
}